﻿using System.Windows;
using System.Windows.Media.Animation;

namespace TotalApplication.AngelSix
{
    /// <summary>
    /// Helpers to animate framework elements in specific ways
    /// </summary>
    public static class FrameworkElementPageAnimations
    {
        #region Slide to left

        /// <summary>
        /// Slide and fade in from left to center
        /// </summary>
        /// <param name="element">the element to animate</param>
        /// <param name="seconds">Animation Seconds</param>
        /// <param name="keepMargin">Wheather to keep the element at the same width during animation</param>
        /// <param name="width">The animation width to animate to. If not specified the elements width</param>
        /// <returns></returns>
        public static async Task SlideAndFadeInFromLeftAsync(this FrameworkElement element, float seconds = 0.3f, bool keepMargin = true, double width = 0)
        {
            var sb = new Storyboard();

            element.Visibility = Visibility.Visible;

            sb.AddSlideFromLeft(width == 0 ? element.ActualWidth : width, seconds, keepMargin: keepMargin);

            sb.AddFadeIn(seconds, false);

            sb.Begin(element);

            await Task.Delay((int)(seconds * 1000));
        }

        /// <summary>
        /// Slide and fade out from center to left
        /// </summary>
        /// <param name="element">the element to animate</param>
        /// <param name="seconds">Animation Seconds</param>
        /// <param name="keepMargin">Wheather to keep the element at the same width during animation</param>
        /// <param name="width">The animation width to animate to. If not specified the elements width</param>
        /// <returns></returns>
        public static async Task SlideAndFadeOutToLeftAsync(this FrameworkElement element, float seconds = 0.3f, bool keepMargin = true, double width = 0)
        {
            var sb = new Storyboard();

            sb.AddSlideToLeft(width == 0 ? element.ActualWidth : width, seconds, keepMargin: keepMargin);

            sb.AddFadeOut(seconds, false);

            sb.Begin(element);

            element.Visibility = Visibility.Visible;

            await Task.Delay((int)(seconds * 1000));

            element.Visibility = Visibility.Collapsed;
        }
        #endregion

        #region Slide to right
        /// <summary>
        /// Slide and fade in from right to center
        /// </summary>
        /// <param name="element">the element to animate</param>
        /// <param name="seconds">Animation Seconds</param>
        /// <param name="keepMargin">Wheather to keep the element at the same width during animation</param>
        /// <param name="width">The animation width to animate to. If not specified the elements width</param>
        /// <returns></returns>
        public static async Task SlideAndFadeInFromRightAsync(this FrameworkElement element, float seconds = 0.3f, bool keepMargin = true, double width = 0)
        {
            // new storyboard
            var sb = new Storyboard();

            // let this page visible
            element.Visibility = Visibility.Visible;

            // [storyboad's extension funcs] Thickness Animation for thickness
            sb.AddSlideFromRight(width == 0 ? element.ActualWidth : width, seconds, keepMargin: keepMargin);

            // Double Animation for Opacity
            sb.AddFadeIn(seconds, true);

            // Intended Target [this page] and begin
            sb.Begin(element);

            // Waiting for animation ends
            await Task.Delay(TimeSpan.FromSeconds((int)(seconds * 1000)));
        }


        /// <summary>
        /// Slide and fade out from center to right
        /// </summary>
        /// <param name="element">the element to animate</param>
        /// <param name="seconds">Animation Seconds</param>
        /// <param name="keepMargin">Wheather to keep the element at the same width during animation</param>
        /// <param name="width">The animation width to animate to. If not specified the elements width</param>
        /// <returns></returns>
        public static async Task SlideAndFadeOutToRightAsync(this FrameworkElement element, float seconds = 0.3f, bool keepMargin = true, double width = 0)
        {
            var sb = new Storyboard();

            sb.AddSlideToRight(width == 0 ? element.ActualWidth : width, seconds, keepMargin: keepMargin);

            sb.AddFadeOut(seconds, false);

            sb.Begin(element);

            element.Visibility = Visibility.Visible;

            await Task.Delay(TimeSpan.FromSeconds((int)(seconds * 1000)));

            element.Visibility = Visibility.Collapsed;
        }

        #endregion

        #region Slide to bottom

        /// <summary>
        /// Slide and fade in from bottom to center
        /// </summary>
        /// <param name="element">the element to animate</param>
        /// <param name="seconds">Animation Seconds</param>
        /// <param name="keepMargin">Wheather to keep the element at the same height during animation</param>
        /// <param name="height">The animation height to animate to. If not specified the elements height</param>
        /// <returns></returns>
        public static async Task SlideAndFadeInFromBottomAsync(this FrameworkElement element, float seconds = 0.3f, bool keepMargin = true, double height = 0)
        {
            var sb = new Storyboard();

            element.Visibility = Visibility.Visible;

            sb.AddSlideFromBottom(height == 0 ? element.ActualHeight : height, seconds, keepMargin: keepMargin);

            sb.AddFadeIn(seconds, false);

            sb.Begin(element);

            await Task.Delay((int)(seconds * 1000));
        }

        /// <summary>
        /// Slide and fade out from center to bottom
        /// </summary>
        /// <param name="element">the element to animate</param>
        /// <param name="seconds">Animation Seconds</param>
        /// <param name="keepMargin">Wheather to keep the element at the same height during animation</param>
        /// <param name="height">The animation height to animate to. If not specified the elements height</param>
        /// <returns></returns>
        public static async Task SlideAndFadeOutToBottomAsync(this FrameworkElement element, float seconds = 0.3f, bool keepMargin = true, double height = 0)
        {
            var sb = new Storyboard();

            sb.AddSlideToBottom(height == 0 ? element.ActualHeight : height, seconds, keepMargin: keepMargin);

            sb.AddFadeOut(seconds, false);

            sb.Begin(element);

            element.Visibility = Visibility.Visible;

            await Task.Delay((int)(seconds * 1000));

            element.Visibility = Visibility.Collapsed;
        }
        #endregion

        #region Fade in/out

        /// <summary>
        /// Fade in 
        /// </summary>
        /// <param name="element">the element to animate</param>
        /// <param name="seconds">Animation Seconds</param>
        /// <returns></returns>
        public static async Task FadeInAsync(this FrameworkElement element,bool firstLoad, float seconds = 0.3f)
        {
            var sb = new Storyboard();

            sb.AddFadeIn(seconds, false);

            sb.Begin(element);

            // Make page visible only if we are animating or its the first load
            if (seconds != 0 || firstLoad)
                element.Visibility = Visibility.Visible;

            await Task.Delay((int)(seconds * 1000));
        }

        /// <summary>
        /// Fade out 
        /// </summary>
        /// <param name="element">the element to animate</param>
        /// <param name="seconds">Animation Seconds</param>
        /// <returns></returns>
        public static async Task FadeOutAsync(this FrameworkElement element, bool firstLoad, float seconds = 0.3f)                                                                                                                                                          
        {
            var sb = new Storyboard();

            sb.AddFadeOut(seconds, false);

            sb.Begin(element);

            // Make page visible only if we are animating or its the first load
            if (seconds != 0 || firstLoad)
                element.Visibility = Visibility.Visible;

            await Task.Delay((int)(seconds * 1000));

            element.Visibility = Visibility.Collapsed;
        }
        #endregion
    }
}
